import Timekeeper
import pygame
import Graphics
import G
import Text
import Vector
import Util
import Config
import copy
import Keys

focus = None
default = lambda: None
defscrollbarwidth = 20

defcolor = (255,255,255)
hovercolor = (128,255,128)
presscolor = (128,128,255)

def leftclick(mouse=False, group=G.UI, owner=None):
   global focus
   
   if mouse == False:
      mouse = pygame.mouse.get_pos()
   if owner is None:
      focus = None
   else:
      owner.focus = None
   for el in group:
      if el.rect.collidepoint(mouse):
         if owner is None:
            focus = el
         else:
            owner.focus = el
         if isinstance(el, UIElement):
            el.press(mouse)

def leftrelease():
   for button in G.pressed_buttons:
      button.release()

def midclick(mouse=False, group=G.UI, owner=None):
   pass

def midrelease():
   pass

def rightclick(mouse=False, group=G.UI, owner=None):
   pass

def rightrelease():
   pass
   
def scrollup(mouse=False, group=G.UI, owner=None):
   if mouse == False:
      mouse = pygame.mouse.get_pos()
   if owner is None:
      cur_focus = focus
   else:
      cur_focus = owner.focus
   if cur_focus is not None and cur_focus.scrolling:
      cur_focus.scrollup()

def scrolluprelease():
   pass
   
def scrolldown(mouse=False, group=G.UI, owner=None):
   if mouse == False:
      mouse = pygame.mouse.get_pos()
   if owner is None:
      cur_focus = focus
   else:
      cur_focus = owner.focus
   if cur_focus is not None and cur_focus.scrolling:
      cur_focus.scrolldown()

def scrolldownrelease():
   pass

clickfuncs = {1: leftclick,
              2: midclick,
              3: rightclick,
              4: scrollup,
              5: scrolldown}
releasefuncs = {1: leftrelease,
                2: midrelease,
                3: rightrelease,
                4: scrolluprelease,
                5: scrolldownrelease}

def click(button):
   clickfuncs.get(button, default)()

def release(button):
   releasefuncs.get(button, default)()
   
class UIElement(pygame.sprite.Sprite):
   __slots__ = ('scrolling',
                'button',
                'typing')
   
   def __init__(self, image, pos, anchor='topleft', button=False, scrolling=False,
                typing=False, group=G.UI):
      pygame.sprite.Sprite.__init__(self)
      self.image = image
      self.rect = image.get_rect()
      offset = Graphics.pos_dict[anchor]
      self.rect.topleft = [pos[0] - offset[0] * self.rect.width,
                           pos[1] - offset[1] * self.rect.height]
      self.scrolling = scrolling
      self.button = button
      self.typing = typing
      if group is not None:
         group.add(self)

   def has_focus(self):
      return focus == self

   def press(self, pos):
      pass
   
   def update(self, mouse=False):
      pass

class Label(UIElement):
   
   def __init__(self, text, pos, color=(255,255,255), fontname=Config.default_font,
                fontsize=Config.default_font_size, bold=False, italic=False, 
                background=None, **args):
      pygame.sprite.Sprite.__init__(self)
      
      if background is not None:
         image = Text.font(fontname, fontsize, bold, italic).render(text, 1, 
                                                                    color,
                                                                    background)
      else:
         image = Text.font(fontname, fontsize, bold, italic).render(text, 1, 
                                                                    color)
      UIElement.__init__(self, image, pos, button=False, scrolling=False, **args)


class Entry(UIElement):
   __slots__ = ('font',
                'width',
                'text',
                'background',
                'color')
   
   def __init__(self, text, pos, width, color=(255,255,255), fontname=Config.default_font,
                fontsize=Config.default_font_size, bold=False, italic=False, 
                background=None, **args):
      pygame.sprite.Sprite.__init__(self)
      
      self.background = background
      self.font = Text.font(fontname, fontsize, bold, italic)
      self.text = text
      self.width = width
      self.color = color
      
      UIElement.__init__(self, self.render(), pos, typing=True, **args)
      
      self.update_image()
   
   def backspace(self):
      if len(self.text) > 0:
         self.text = self.text[0:-1]
         self.update_image()
   
   def render(self):
      if self.background is not None:
         return self.font.render(self.text, 1, self.color, self.background)
      else:
         return self.font.render(self.text, 1, self.color)
   
   def settext(self, text):
      self.text = text
      self.update_image()
   
   def type(self, key):
      self.text = "%s%s" % (self.text, key)
      self.update_image()
   
   def update_border(self):
      if focus is self:
         color = (128,128,255)
      else:
         color = (255,255,255)
      pygame.draw.rect(self.image, color, self.image.get_rect(), 1)
   
   def update_image(self):
      pos = self.rect.topleft
      im = self.render()
      self.image = pygame.Surface((self.width, im.get_rect().height+10))
      self.image.blit(im, (5,5))
      self.update_border()
      self.rect = self.image.get_rect()
      self.rect.topleft = pos
   
   def update(self, mouse=False):
      UIElement.update(self, mouse)
      self.update_border()
      
class TextBox(UIElement):
   __slots__ = ('width',
                'font',
                'color',
                'background')
   
   def __init__(self, text, pos, width, color=(255,255,255), fontname=Config.default_font,
                fontsize=Config.default_font_size, bold=False, italic=False, 
                background=None, **args):
      pygame.sprite.Sprite.__init__(self)
      
      self.width = width
      self.font = Text.font(fontname, fontsize, bold, italic)
      self.color = color
      self.background = background
      
      self.rect = None
      
      self.settext(text)
      
      UIElement.__init__(self, self.image, pos, button=False, scrolling=False, **args)
   
   def render(self, text):
      if self.background is not None:
         return self.font.render(text, 1, self.color, self.background)
      else:
         return self.font.render(text, 1, self.color)
   
   def settext(self, text):
      lines = list()
      height = 0
      
      if self.rect is not None:
         tl = self.rect.topleft
      else:
         tl = None
      
      text = text.strip()
      textlines = list()
      part = text.partition('\n')
      
      def specsplit(line):
         line = line.rstrip()
         words = list()
         while len(line) > 0:
            i = 0
            while i < len(line) and line[i] == ' ':
               i += 1
            while i < len(line) and line[i] != ' ':
               i += 1
            words.append(line[:i])
            line = line[i:]
         return words
            
      while len(part[1]) > 0:
         textlines.append(specsplit(part[0]))
         if len(textlines[-1]) == 0:
            textlines[-1] = [""]
         part = part[2].partition('\n')
      textlines.append(specsplit(part[0]))
      if len(textlines[-1]) == 0:
         textlines[-1] = [""]
      
      for words in textlines:
         while len(words) > 0:
            cur_string = ""
            if self.font.size(words[0])[0] > self.width:
               i = 1
               while self.font.size(words[0][:i])[0] < self.width:
                  i += 1
               cur_string = words[0][:i-1]
               words[0] = words[0][i:]
            else:
               cur_string = words.pop(0)
               if len(words) > 0:
                  size = self.font.size(words[0])
                  while len(words) > 0 and \
                        self.font.size(cur_string)[0] + \
                        self.font.size("%s" % words[0])[0] < self.width:
                     cur_string = "%s%s" % (cur_string, words.pop(0))
            lines.append(self.render(cur_string.strip()))
            height += int(lines[-1].get_rect().height * 1.1)
      
      self.image = pygame.Surface((self.width, height))
      if self.background is not None:
         self.image.fill(self.background)
      y = 0
      for line in lines:
         self.image.blit(line, (0, y))
         y += int(line.get_rect().height*1.1)
      self.rect = self.image.get_rect()
      
      if tl is not None:
         self.rect = self.image.get_rect()
         self.rect.topleft = tl

class Button(UIElement):
   __slots__ = ('hoverimage',
                'pressimage',
                'function',
                'hovering',
                'pressed',
                'origimage',
                'pad')
   
   def __init__(self, image, pos, function=lambda: None, pad=0,
                hoverimage=None, pressimage=None, **args):
      UIElement.__init__(self, image, pos, button=True, **args)
      self.origimage = self.image
      if hoverimage is None:
         self.hoverimage = image
      else:
         self.hoverimage = hoverimage
      if pressimage is None:
         self.pressimage = image
      else:
         self.pressimage = pressimage
      self.pad = pad
      self.rect.inflate_ip(pad*2, pad*2)
      self.function = function
      self.hovering = False
      self.pressed = False
   
   def hover(self):
      self.hovering = True
      self.set_image()
   
   def press(self, pos):
      UIElement.press(self, pos)
      self.pressed = True
      self.set_image()
      G.pressed_buttons.append(self)
   
   def set_image(self):
      if self.pressed:
         self.image = self.pressimage
      elif self.hovering:
         self.image = self.hoverimage
      else:
         self.image = self.origimage
   
   def unhover(self):
      self.hovering = False
      self.set_image()
   
   def release(self):
      self.pressed = False
      self.set_image()
      G.pressed_buttons.remove(self)
      self.function()
   
   def update(self, mouse=False):
      if mouse is not None:
         if not mouse:
            mouse = pygame.mouse.get_pos()
         if not self.hovering and self.rect.collidepoint(mouse):
            self.hover()
         elif self.hovering and not self.rect.collidepoint(mouse):
            self.unhover()

class TextButton(Button):
   __slots__ = ('text',
                'background',
                'maincolor',
                'hovercolor',
                'presscolor',
                'font')

   def __init__(self, text, font, pos, maincolor=defcolor, hovercolor=hovercolor, 
                presscolor=presscolor, background=(0,0,0), **args):
      self.font = font
      self.text = text
      self.background = background
      self.maincolor = maincolor
      self.hovercolor = hovercolor
      self.presscolor = presscolor
      image = self.render(maincolor)
      hoverimage = self.render(hovercolor)
      pressimage = self.render(presscolor)
      Button.__init__(self, image, pos, hoverimage=hoverimage, 
                      pressimage=pressimage, **args)
   
   def render(self, color):
      if self.background is not None:
         return self.font.render(self.text, 1, color, self.background)
      else:
         return self.font.render(self.text, 1, color)
   
   def settext(self, text):
      self.text = text
      pos = self.rect.topleft
      self.origimage = self.render(self.maincolor)
      self.hoverimage = self.render(self.hovercolor)
      self.pressimage = self.render(self.presscolor)
      self.set_image()
      
      self.rect = self.image.get_rect()
      self.rect.topleft = pos

def generatetextbuttons(textfuncs, font, x, ystart, ystep, *args, **kwargs):
   y = ystart
   for t, f in textfuncs:
      TextButton(t, font, (x, y), function=f, *args, **kwargs)
      y += ystep

class RadioButton(Button):
   __slots__ = ('buttongroup',
                'selected'
                'sorigimage',
                'shoverimage',
                'spressimage',
                'oldbutton',
                'bgcolor')
   
   def __init__(self, buttongroup, selectcolor=(128,128,196), bgcolor=None, 
                oldbutton=None, **args):
      Button.__init__(self, **args)
      self.oldbutton = oldbutton
      self.buttongroup = buttongroup
      self.selected = False
      self.selectcolor = selectcolor
      if bgcolor is None:
         self.bgcolor = self.image.get_at((0,0))
      else:
         self.bgcolor = bgcolor
      for t in ('orig', 'hover', 'press'):
         self.change_image(getattr(self,'%simage' % t), t)

   def change_image(self, newimage, t='orig', bgcolor=None):
      if bgcolor is not None:
         self.bgcolor = bgcolor
      transparentimage = newimage.copy()
      imagerect = transparentimage.get_rect()
      if transparentimage.get_colorkey() is None:
         transparentimage.set_colorkey(self.bgcolor)
      setattr(self, 's%simage' % t, pygame.Surface(imagerect.size))
      newimage = getattr(self, 's%simage' % t)
      newimage.fill(self.selectcolor)
      newimage.blit(transparentimage, (0,0))
      self.set_image()
   
   def deselect(self):
      self.selected = False
      self.set_image()
      
   @classmethod
   def from_button(cls, button, buttongroup, **newargs):
      args = {'anchor': 'topleft'}
      for var in ('image', 'hoverimage', 'pressimage'):
         args[var] = getattr(button, var).copy()
      args['function'] = copy.deepcopy(button.function)
      args['pos'] = button.rect.topleft
      args['pad'] = button.pad
      args['group'] = button.groups()[0]
      args.update(newargs)
      args['oldbutton'] = button
      button.kill()
      button.oldgroups = button.groups()
      return RadioButton(buttongroup, **args)
   
   def kill(self):
      if self.oldbutton is not None:
         for g in self.oldbutton.oldgroups:
            g.add(self.oldbutton)
      pygame.sprite.Sprite.kill(self)
   
   def release(self):
      if self.selected:
         self.deselect()
      else:
         self.select()
      Button.release(self)
   
   def select(self):
      for button in self.buttongroup:
         button.deselect()
      self.selected = True
      self.set_image()
   
   def set_image(self):
      if self.selected:
         if self.pressed:
            self.image = self.spressimage
         elif self.hovering:
            self.image = self.shoverimage
         else:
            self.image = self.sorigimage
      else:
         if self.pressed:
            self.image = self.pressimage
         elif self.hovering:
            self.image = self.hoverimage
         else:
            self.image = self.origimage

class KeyMapButton(RadioButton):
   __slots__ = ('text',
                'background',
                'maincolor',
                'hovercolor',
                'presscolor',
                'font',
                'width',
                'height',
                'command',
                'keys')
   
   def __init__(self, command, font, pos, width, buttongroup=list(), selectcolor=(50,50,100), 
                maincolor=defcolor, hovercolor=hovercolor, 
                presscolor=presscolor, background=(0,0,0),
                **kwargs):
      self.command = command
      self.font = font
      self.buttongroup = buttongroup
      self.width = width
      self.keys = list()
      for k, v in Keys.keynames.items():
         if v == self.command:
            self.keys.append(k)
      self.keys.sort()
      self.height = font.size(command)[1]
      self.selectcolor = selectcolor
      self.background = background
      self.maincolor = maincolor
      self.hovercolor = hovercolor
      self.presscolor = presscolor
      image = self.render(maincolor)
      hoverimage = self.render(hovercolor)
      pressimage = self.render(presscolor)
      self.sorigimage = self.render(maincolor, bg=selectcolor)
      self.shoverimage = self.render(hovercolor, bg=selectcolor)
      self.spressimage = self.render(presscolor, bg=selectcolor)
      self.selected = False
      def f():
         Keys.listenbutton = self
      kwargs['function'] = f
      Button.__init__(self, image, pos, hoverimage=hoverimage, 
                      pressimage=pressimage, **kwargs)
   
   def add_key(self, key):
      for b in self.buttongroup:
         b.remove_key(key)
      self.keys.append(key)
      self.keys.sort()
      self.settext()
   
   def def_text(self):
      return "%s: %s" % (self.command, ', '.join(map(pygame.key.name, self.keys)))
   
   def remove_key(self, key):
      if key in self.keys:
         self.keys.remove(key)
      self.settext()
   
   def render(self, color, bg=None):
      im = pygame.Surface((self.width, self.height))
      if bg is None:
         bg = self.background
      im.fill(bg)
      im.blit(self.font.render(self.def_text(), 1, color), (0,0))
      return im
   
   def settext(self, text=None):
      if text is None:
         text = self.def_text()
      self.text = text
      pos = self.rect.topleft
      self.origimage = self.render(self.maincolor)
      self.hoverimage = self.render(self.hovercolor)
      self.pressimage = self.render(self.presscolor)
      self.sorigimage = self.render(self.maincolor, bg=self.selectcolor)
      self.shoverimage = self.render(self.hovercolor, bg=self.selectcolor)
      self.spressimage = self.render(self.presscolor, bg=self.selectcolor)
      self.set_image()
      
      self.rect = self.image.get_rect()
      self.rect.topleft = pos

class ButtonList(UIElement):
   __slots__ = ('buttons',
                'selectcolor',
                'buttonargs')

   def __init__(self, buttons=None, **args):
      self.buttons = list()
      self.buttonargs = args
      if buttons is not None:
         self.setbuttons(buttons)
   
   def addbutton(self, button):
      self.buttons.append(RadioButton.from_button(button, self.buttons, **self.buttonargs))
   
   def kill(self):
      for button in self.buttons:
         button.kill()
      pygame.sprite.Sprite.kill(self)
   
   def selected(self):
      for i, button in enumerate(self.buttons):
         if button.selected:
            return i
      return -1
   
   def setbuttons(self, buttons):
      self.buttons = list()
      for button in buttons:
         self.addbutton(button)

def ListBox(buttonimages, widthmult=1.3, heightmult=1.1, **args):
   heights = list()
   totalheight = 0
   maxwidth = 0
   
   for image in buttonimages:
      w, h = image.get_rect().size
      totalheight += h
      heights.append(h)
      if w > maxwidth:
         maxwidth = w
   
   subwindow = pygame.Surface((int(maxwidth*widthmult), int(totalheight*heightmult)))
   
   buttons = list()
   bl = ButtonList()
   
   y = 0
   for i,image in enumerate(buttonimages):
      buttons.append(Button(image, [10, y], **args))
      y += int(heights[i]*heightmult)
   
   bl.setbuttons(buttons)
   
   return bl, subwindow

class Scroller(UIElement, Timekeeper.Timekeeper):
   
   __slots__ = ('fullimage',
                'background',
                'focus',
                'embeddedobjects',
                'embeddedspreites',
                'arrowpressed',
                'barpressed',
                'scrollbarpoint',
                'imagesize',
                'lastclick',
                'holdtime',
                'holddelay',
                'holdclickinterval',
                'fgcolor',
                'bgcolor',
                'scrollbarwidth',
                'imagewindow',
                'imagerect',
                'oldhorscrollpos',
                'horscrollpos',
                'horscrollbar',
                'horscrollarea',
                'hortracklen',
                'uparrow',
                'downarrow',
                'leftarrow',
                'rightarrow',
                'oldvertscrollpos',
                'vertscrollpos',
                'vertscrollbar',
                'vertscrollarea',
                'verttracklen')
   
   def __init__(self, image, pos, dimensions, anchor='topleft', scrollbarwidth=defscrollbarwidth,
                fgcolor=(255,255,255), bgcolor=(0,0,0), scrollamount=0.15, 
                holddelay=0.5, holdclickinterval=0.15, **args):
      self.embeddedobjects = pygame.sprite.Group()
      self.embeddedsprites = pygame.sprite.Group()
      self.vertscrollbar = None
      self.horscrollbar = None
      self.vertscrollarea = None
      self.horscrollarea = None
      self.leftarrow = None
      self.rightarrow = None
      self.uparrow = None
      self.downarrow = None
      self.horscrollpos = 0
      self.vertscrollpos = 0
      self.oldhorscrollpos = None
      self.oldvertscrollpos = None
      self.lastclick= (0,0)
      self.arrowpressed = False
      self.barpressed = None
      self.holdtime = 0.0
      self.scrollbarpoint = None
      self.holddelay = holddelay
      self.holdclickinterval = holdclickinterval
      self.scrollbarwidth = scrollbarwidth
      self.fgcolor = fgcolor
      self.bgcolor = bgcolor
      self.focus = None
      
      self.background = image
      self.imagesize = image.get_rect().size
      self.fullimage = pygame.Surface(self.imagesize)
      dimensions = list(dimensions)
      vertscroll = False
      horscroll = False
      if dimensions[1] < self.imagesize[1]:
         if dimensions[0] - scrollbarwidth < self.imagesize[0]:
            vertscroll = True
            horscroll = True
         else:
            vertscroll = True
      if dimensions[0] < self.imagesize[0]:
         if dimensions[1] - scrollbarwidth < self.imagesize[1]:
            vertscroll = True
            horscroll = True
         else:
            horscroll = True
      
      windowsize = [0,0]
      
      def setwindowsize():
         windowsize[0] = dimensions[0]
         windowsize[1] = dimensions[1]
         if vertscroll:
            windowsize[0] -= scrollbarwidth
         if horscroll:
            windowsize[1] -= scrollbarwidth
      
      setwindowsize()
      
      for i in (0, 1):
         if self.imagesize[i] < windowsize[i]:
            diff = windowsize[i] - self.imagesize[i]
            dimensions[i] -= diff
      setwindowsize()
      
      self.imagewindow = pygame.Surface(windowsize)
      self.imagerect = self.imagewindow.get_rect()
      self.image = pygame.Surface(dimensions)
      self.image.fill(bgcolor)
      UIElement.__init__(self, self.image, pos, anchor, scrolling=True, **args)
      
      w, h = windowsize
      if vertscroll:
         toparrow = [(w + scrollbarwidth/2, scrollbarwidth/3),
                     (w + scrollbarwidth*2/3, scrollbarwidth*3/4),
                     (w + scrollbarwidth/3, scrollbarwidth*3/4)]
         if horscroll:
            bottompad = scrollbarwidth
         else:
            bottompad = 0
         bottomarrow = [(x, h - y) for x,y in toparrow]
         pygame.draw.polygon(self.image, fgcolor, toparrow)
         pygame.draw.polygon(self.image, fgcolor, bottomarrow)
         self.toparrow = pygame.Rect(w, 0, scrollbarwidth, scrollbarwidth)
         self.bottomarrow = pygame.Rect(w, h-scrollbarwidth, scrollbarwidth, scrollbarwidth)
         self.vertscrollarea = pygame.Rect(w, scrollbarwidth,
                                           scrollbarwidth, h - 2*scrollbarwidth)
         self.vertscrollbar = pygame.Rect(w, scrollbarwidth,
                                           scrollbarwidth, int(1.0 * self.vertscrollarea.height * h / self.imagesize[1]))
         self.verttracklen = h - 2*scrollbarwidth
      if horscroll:
         leftarrow = [(scrollbarwidth/3, h + scrollbarwidth/2),
                     (scrollbarwidth*3/4, h + scrollbarwidth*2/3),
                     (scrollbarwidth*3/4, h + scrollbarwidth/3)]
         if vertscroll:
            rightpad = scrollbarwidth
         else:
            rightpad = 0
         rightarrow = [(w - x, y) for x,y in leftarrow]
         pygame.draw.polygon(self.image, fgcolor, leftarrow)
         pygame.draw.polygon(self.image, fgcolor, rightarrow)
         self.leftarrow = pygame.Rect(0, h, scrollbarwidth, scrollbarwidth)
         self.rightarrow = pygame.Rect(w-scrollbarwidth, h, scrollbarwidth, scrollbarwidth)
         self.horscrollarea = pygame.Rect(scrollbarwidth, h,
                                           w - 2*scrollbarwidth, scrollbarwidth)
         self.horscrollbar = pygame.Rect(scrollbarwidth, h,
                                           int(1.0 * self.horscrollarea.width * w / self.imagesize[0]), scrollbarwidth)
         self.hortracklen = w - 2*scrollbarwidth
   
   @classmethod
   def fromobject(cls, element, pos, dimensions, *args, **kwargs):
      imagesurface = pygame.Surface(element.image.get_rect().size)
      s = cls(imagesurface, pos, dimensions, *args, **kwargs)
      element.kill()
      s.embeddedobjects.add(element)
      return s
   
   def getimagepos(self, truepos):
      return (int((self.imagesize[0] - self.imagerect.width)*self.horscrollpos) + truepos[0],
               (int(self.imagesize[1] - self.imagerect.height)*self.vertscrollpos) + truepos[1])
   
   def gettruepos(self, pos):
      return Vector.v_sub(pos, self.rect.topleft)
   
   def kill(self):
      self.embeddedobjects.empty()
      pygame.sprite.Sprite.kill(self)
   
   def press(self, pos, fake=False):
      mouse = pygame.mouse.get_pos()
      truepos = self.gettruepos(mouse)
      imagepos = self.getimagepos(truepos)
      self.lastclick = mouse
      if self.imagerect.collidepoint(truepos):
         leftclick(mouse=imagepos, group=self.embeddedobjects, owner=self)
      elif self.horscrollbar is not None and self.horscrollbar.collidepoint(truepos):
         self.barpressed = self.horscrollbar
         self.scrollbarpoint = Vector.v_sub(truepos, self.horscrollbar.topleft)
         G.pressed_buttons.append(self)
      elif self.vertscrollbar is not None and self.vertscrollbar.collidepoint(truepos):
         self.barpressed = self.vertscrollbar
         self.scrollbarpoint = Vector.v_sub(truepos, self.vertscrollbar.topleft)
         G.pressed_buttons.append(self)
      else:
         arrows = (self.toparrow, self.bottomarrow,
                   self.leftarrow, self.rightarrow)
         if not fake:
            self.arrowpressed = True
            G.pressed_buttons.append(self)
         for arrow in arrows:
            if arrow is not None and arrow.collidepoint(truepos):
               if arrow is self.toparrow:
                  self.scrollup()
               elif arrow is self.bottomarrow:
                  self.scrolldown()
               elif arrow is self.leftarrow:
                  self.scrollleft()
               else:
                  self.scrollright()
   
   def scrolldown(self, amount=0.05):
      self.vertscrollpos = Util.constrain(self.vertscrollpos+amount,0.0,1.0)
   
   def scrollleft(self, amount=0.05):
      self.horscrollpos = Util.constrain(self.horscrollpos-amount,0.0,1.0)
   
   def scrollright(self, amount=0.05):
      self.horscrollpos = Util.constrain(self.horscrollpos+amount,0.0,1.0)
   
   def scrollup(self, amount=0.05):
      self.vertscrollpos = Util.constrain(self.vertscrollpos-amount,0.0,1.0)
   
   def release(self):
      self.barpressed = None
      self.arrowpressed = False
      self.holdtime = 0.0
      G.pressed_buttons.remove(self)
   
   def update(self):
      mouse = pygame.mouse.get_pos()
      truepos = self.gettruepos(mouse)
      imagepos = self.getimagepos(truepos)
      if self.imagerect.collidepoint(truepos):
         self.embeddedobjects.update(imagepos)
      else:
         self.embeddedobjects.update(None)
      self.embeddedsprites.update()
      self.fullimage.blit(self.background, (0,0))
      self.embeddedobjects.draw(self.fullimage)
      self.embeddedsprites.draw(self.fullimage)
      if self.barpressed is not None:
         if self.barpressed is self.horscrollbar:
            newleft = truepos[0] - self.scrollbarpoint[0] - self.horscrollarea.left
            space = self.hortracklen - self.horscrollbar.width
            self.horscrollpos = Util.constrain(1.0 * (newleft) / space, 0.0, 1.0)
         else:
            newtop = truepos[1] - self.scrollbarpoint[1] - self.vertscrollarea.top
            space = self.verttracklen - self.vertscrollbar.height
            self.vertscrollpos = Util.constrain(1.0 * (newtop) / space, 0.0, 1.0)
      elif self.arrowpressed:
         self.holdtime += self.frame()
         if self.holdtime > self.holddelay:
            clicks = 0
            while self.holdtime > self.holddelay + self.holdclickinterval:
               clicks += 1
               self.holdtime -= self.holdclickinterval
            for i in range(0, clicks):
               self.press(self.lastclick, fake=True)
      if self.oldhorscrollpos != self.horscrollpos:
         self.oldhorscrollpos = self.horscrollpos
         self.updatescrollpos(vert=False)
      if self.oldvertscrollpos != self.vertscrollpos:
         self.oldvertscrollpos = self.vertscrollpos
         self.updatescrollpos()
      self.updatedisplayimage()
   
   def updatedisplayimage(self):
      w, h = self.imagerect.size
      tw, th = self.fullimage.get_rect().size
      pos = self.rect.topleft
      displayrect = pygame.Rect(int(self.horscrollpos * (tw - w)),
                                int(self.vertscrollpos * (th - h)),
                                w, h)
      self.image.blit(self.fullimage.subsurface(displayrect), (0,0))
   
   def updatescrollpos(self, vert=True):
      bar = None
      if vert:
         if self.vertscrollbar is not None:
            bar = self.vertscrollbar
            pos = self.vertscrollpos
            space = self.verttracklen - bar.height
      else:
         if self.horscrollbar is not None:
            bar = self.horscrollbar
            pos = self.horscrollpos
            space = self.hortracklen - bar.width
      if bar is not None:
         newpos = int(pos * space)
         if vert:
            if self.vertscrollbar is not None:
               bar.top = newpos + self.scrollbarwidth
               pygame.draw.rect(self.image, self.bgcolor, self.vertscrollarea)
               pygame.draw.rect(self.image, self.fgcolor, self.vertscrollbar)
         else:
            if self.horscrollbar is not None:
               bar.left = newpos + self.scrollbarwidth
               pygame.draw.rect(self.image, self.bgcolor, self.horscrollarea)
            pygame.draw.rect(self.image, self.fgcolor, self.horscrollbar)
